-- 一个合并函数
local function CombineTags(tags1, tags2)
    if tags2 ~= nil then
        for _, v in pairs(tags2) do
            table.insert(tags1, v)
        end
    end
    return tags1
end
-- 建筑与伙伴标签,代码作者:梧桐
local function TagsFriendly(othertags)
    return CombineTags({
        "INLIMBO", "NOCLICK", "notarget", "noattack", "playerghost",
        "wall", "structure", "balloon",
        "companion", "glommer", "friendlyfruitfly", "abigail", "shadowminion"
    }, othertags)
end

--==============================
--[[ 草莓酱buff相关函数 ]]
--==============================
local spdamage = {
    planar = 20,
}
local function strawberry_jam(owner, data)
    -- 范围伤害
    -- 根据有无启用PvP,排除玩家标签
    local target = data.target
    if target == nil or data.weapon == nil then
        return
    end
    local fx = SpawnPrefab("slingshotammo_gunpowder_explode")
    if fx ~= nil then
        fx.Transform:SetPosition(target.Transform:GetWorldPosition())
    end
    target.components.combat:GetAttacked(data.weapon or target, 0, nil, nil, spdamage)

    local friendlyTags = TagsFriendly(TheNet:GetPVPEnabled() and {} or { "player" })
    local x, y, z = target.Transform:GetWorldPosition()
    -- 查找范围4加上物理半径内的所有实体，排除友好单位
    local entities = TheSim:FindEntities(x, y, z, 4, nil, friendlyTags)
    for _, entity in ipairs(entities) do
        if entity ~= owner and entity ~= target and entity.components.combat then
            entity.components.combat:GetAttacked(data.weapon or target, 0, nil, nil, spdamage)
            if entity.components.health and entity.components.health:IsDead() then
                owner:PushEvent("killed", { victim = entity, attacker = owner })
                if entity.components.combat.onkilledbyother ~= nil then
                    entity.components.combat.onkilledbyother(entity, owner)
                end
            end
        end
    end
end

--==============================
--[[ 橘子酱buff相关函数 ]]
--==============================
local function no_aggro(attacker, target)
    local targets_target = target.components.combat ~= nil and target.components.combat.target or nil
    return targets_target ~= nil and targets_target:IsValid() and targets_target ~= attacker and attacker ~= nil and attacker:IsValid()
        and (GetTime() - target.components.combat.lastwasattackedbytargettime) < 4
        and (targets_target.components.health ~= nil and not targets_target.components.health:IsDead())
end

local MAX_JAM_VARIATIONS = 7
local MAX_PICK_INDEX = 3
local JAM_VAR_POOL = { 1 }
for i = 2, MAX_JAM_VARIATIONS do
    table.insert(JAM_VAR_POOL, math.random(i), i)
end

local function PickOrangeJam()
    local rand = table.remove(JAM_VAR_POOL, math.random(MAX_PICK_INDEX))
    table.insert(JAM_VAR_POOL, rand)
    return rand
end

local function TrySpawnOrangeJam(target, min_scale, max_scale, duration)
    local x, y, z = target.Transform:GetWorldPosition()
    if TheWorld.Map:IsPassableAtPoint(x, 0, z) then
        local fx = SpawnPrefab("honey_trail")
        fx.Transform:SetPosition(x, 0, z) -- NOTES(JBK): This must be before SetVariation is called!
        fx:SetVariation(PickOrangeJam(), GetRandomMinMax(min_scale, max_scale), duration + math.random() * .5)
    elseif TheWorld.has_ocean then
        SpawnPrefab("ocean_splash_ripple" .. tostring(math.random(2))).Transform:SetPosition(x, 0, z)
    end
end

local function OnUpdate_OrangeJam(target, t0)
    local elapsed = GetTime() - t0
    if elapsed < 8 then
        local k = 1 - elapsed / 8
        k = k * k * 0.6 + 0.3
        TrySpawnOrangeJam(target, k, k + 0.2, 2)
    else
        target._orange_jamtask:Cancel()
        target._orange_jamtask = nil
        target:RemoveTag("orange_jam_afflicted")
        if target.components.locomotor then
            target.components.locomotor:RemoveExternalSpeedMultiplier(target, "orange_jam_afflicted")
        end
        target:PushEvent("stop_orange_jam_afflicted")
    end
end

local function OnHit_OrangeJam(attacker, data)
    local target = data.target
    if target and target:IsValid() then
        if target:HasTag("orange_jam_afflicted") then
            if data.damage ~= nil and data.damage > 0 then
                local damage = data.damage
                local truedamage = damage * 0.3
                if target.components.health ~= nil and not target:HasTag("playerghost") then
                    target.components.health:DoDelta(-truedamage, nil, "orange_jam_afflicted", nil, attacker, true) --无视防御
                end
                if target.components.health:IsDead() then
                    attacker:PushEvent("killed", { victim = target })
                    if target.components.combat ~= nil and target.components.combat.onkilledbyother ~= nil then
                        target.components.combat.onkilledbyother(target, attacker)
                    end
                end
            end
        end
        local pushstartevent
        if target._orange_jamtask then
            target._orange_jamtask:Cancel()
        else
            target:AddTag("orange_jam_afflicted")
            if target.components.locomotor and not target:HasAnyTag("flying", "playerghost") then
                target.components.locomotor:SetExternalSpeedMultiplier(target, "orange_jam_afflicted", 0.2)
            end
            pushstartevent = true
        end
        target._orange_jamtask = target:DoPeriodicTask(1, OnUpdate_OrangeJam, 0.43, GetTime())

        if not no_aggro(attacker, target) and target.components.combat then
            target:PushEvent("attacked", { attacker = attacker, damage = 0, weapon = data.weapon })
        end

        if pushstartevent then
            target:PushEvent("start_orange_jam_afflicted")
        end
    end
end

--==============================
--[[ buff列表 ]]
--==============================
local buffs = {
    --草莓酱
    strawberry_jam = {
        duration = TUNING.TOTAL_DAY_TIME,
        priority = 1,
        onattachedfn = function(inst, target)
            if target.components.combat ~= nil then
                target:ListenForEvent("onhitother", strawberry_jam)
            end
        end,
        ondetachedfn = function(inst, target)
            if target.components.combat ~= nil then
                target:RemoveEventCallback("onhitother", strawberry_jam)
            end
        end,
    },
    --橘子酱
    orange_jam = {
        duration = TUNING.TOTAL_DAY_TIME,
        priority = 1,
        onattachedfn = function(inst, target)
            if target.components.combat ~= nil then
                target.components.combat.externaldamagemultipliers:SetModifier(inst, 1.05)
                target:ListenForEvent("onhitother", OnHit_OrangeJam)
            end
        end,
        ondetachedfn = function(inst, target)
            if target.components.combat ~= nil then
                target.components.combat.externaldamagemultipliers:RemoveModifier(inst)
                target:RemoveEventCallback("onhitother", OnHit_OrangeJam)
            end
        end,
    },
}

return buffs
